package br.ufpb.di.knowledgetv.sqtv.services;


import br.ufpb.di.knowledgetv.sqtv.utils.SPARQLUtils;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

@Component
public class DbPediaService extends AbstractService {

    private static HttpRequestFactory HTTP_REQUEST_FACTORY;
    private static SAXParserFactory   SAX_PARSER_FACTORY;
    private static DocumentBuilder    DOCUMENT_BUILDER;

    @PostConstruct
    public void createBuilders() {
        try {
            HTTP_REQUEST_FACTORY = new NetHttpTransport().createRequestFactory();
            SAX_PARSER_FACTORY = SAXParserFactory.newInstance();
            DOCUMENT_BUILDER = DocumentBuilderFactory.newInstance().newDocumentBuilder();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

	private String processKeywords(String k) {
		return k.replace("-", "").replace(":", "").replace(",", "").replace("and", "").replace("or", "").replace("  ", " ").replace(" ", " and ").replace(";", " or ");
	}
	
	public List<Resource> searchByKeyword_old(String keyword) {
        List<Resource> result = new ArrayList<Resource>();
        try {
            String sparql = SPARQLUtils.readFileSparql(getClass().getResource("/sparqls/query_dbpedia.sparql").getPath(), keyword);
            ResultSet rs = SPARQLUtils.executeQuery("http://dbpedia.org/sparql", sparql);


            while (rs.hasNext()) {
                QuerySolution qs = rs.next();
                Resource re = qs.getResource("thing");
                re.addLiteral(RDFS.label, qs.getLiteral("label"));
                re.addLiteral(RDFS.comment, qs.getLiteral("abstract"));
                re.addProperty(RDF.type, qs.getResource("type"));
                result.add(re);
            }

        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            return result;
        }
    }

    public List<Resource> searchByKeyword(String keyword) {
        List<Resource> resourcesResult = new ArrayList<Resource>();
        Model model = ModelFactory.createDefaultModel();
        try {
            URI uri = new URI("http://lookup.dbpedia.org/api/search.asmx/KeywordSearch");
            GenericUrl url = new GenericUrl(uri);
            url.set("QueryString", keyword);
            url.set("QueryClass", "work");
            HttpRequest request = HTTP_REQUEST_FACTORY.buildGetRequest(url);
            HttpResponse response = request.execute();
            InputStream responseStream = response.getContent();

            Document document = DOCUMENT_BUILDER.parse(responseStream);
            document.getDocumentElement().normalize();

            NodeList results = document.getDocumentElement().getElementsByTagName("Result");
            for(int i = 0; i < results.getLength(); i++) {
                Element result = (Element) results.item(i);
                String label = result.getElementsByTagName("Label").item(0).getTextContent();
                String nodeUri = result.getElementsByTagName("URI").item(0).getTextContent();
                String description = result.getElementsByTagName("Description").item(0).getTextContent();

                Resource resource = model.createResource(nodeUri);
                resource.addProperty(RDFS.label, label);
                resource.addProperty(RDFS.comment, description);
                resource.addProperty(RDFS.domain, this.beanName);

                Element classes = (Element) result.getElementsByTagName("Classes").item(0);
                NodeList classesList = classes.getElementsByTagName("Class");

                for(int j = 0; j < classesList.getLength(); j++) {
                    Element type = (Element) classesList.item(j);
                    String typeUri = type.getElementsByTagName("URI").item(0).getTextContent();
                    String typeLabel = type.getElementsByTagName("Label").item(0).getTextContent();
                    Resource resourceType = model.createResource(typeUri);
                    resourceType.addProperty(RDFS.label, typeLabel);
                    resource.addProperty(RDF.type, resourceType);
                }

                resourcesResult.add(resource);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return resourcesResult;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public Model getModel(String url) {
        Model model = ModelFactory.createDefaultModel();
        return model.read(url);
    }
}
